package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.dto.MetaMapSettleDTO;
import com.sc.nft.dto.OrderDTO;
import com.sc.nft.dto.UserFirstBuyDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.FlowRecordDTO;
import com.sc.nft.entity.dto.OrderDetailsDTO;
import com.sc.nft.entity.dto.OrderFirstPayDTO;
import com.sc.nft.entity.dto.OrderRushPayDTO;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.MessageQueueHelper;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.util.OrderNoUtil;
import com.sc.nft.util.aliPay.AlipayCore.AliPayCore;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单表服务接口实现
 *
 * @author zxy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2022-06-02 01:04:25
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class OrderServiceImpl implements OrderService {

    private final FilterIncomeListDao filterIncomeListDao;
    private final OrderDao orderDao;
    private final UserConsensusService userConsensusService;

    private final DigitalCollectionProductInfoDao digitalCollectionProductInfoDao;

    private final DigitalCollectionDao digitalCollectionDao;

    private final ProductStockService productStockService;

    private final BoxProductDao boxProductDao;

    private final BoxItemService boxItemService;

    private final UserReceiveIntegralService userReceiveIntegralService;

    private final StaticDataDao staticDataDao;

    private final UserInfoDao userInfoDao;

    private final ExpenditureRecordDao expenditureRecordDao;

    private final ReceiveProductRecordDao receiveProductRecordDao;

    private final PrivilegeDao privilegeDao;

    private final PrivilegeUseLogDao privilegeUseLogDao;

    private final UserCollectionService userCollectionService;

    private final UserCollectionDao userCollectionDao;

    private final BuyFirstCollectionDao buyFirstCollectionDao;

    private final BuyFirstUserDao buyFirstUserDao;

    private final FirstBuyRecordDao firstBuyRecordDao;

    private final OrderFirstBuyDao orderFirstBuyDao;

    private final RushBuyCollectionDao rushBuyCollectionDao;

    private final RushBuyUserDao rushBuyUserDao;

    private final RushBuyRecordDao rushBuyRecordDao;

    private final OrderRushBuyDao orderRushBuyDao;

    private final BuyCollectionDiscountDao buyCollectionDiscountDao;

    private final BuyUserDiscountDao buyUserDiscountDao;

    private final UserWalletDao userWalletDao;

    private final MessageQueueHelper messageQueueHelper;

    private final FilterIncomeListService filterIncomeListService;


    private final EquityPropsService equityPropsService;

    private final UserEquityPropsService userEquityPropsService;

    private final RedisTemplate redisTemplate;

    private final SecondCollectionConfigDao secondCollectionConfigDao;

    private final SecondOrderDao secondOrderDao;

    private final RoughStoneOrderDao roughStoneOrderDao;


    private final Redisson redisson;

    private final DigitalCollectionProductInfoSubscribeDao digitalCollectionProductInfoSubscribeDao;

    private final DigitalCollectionProductInfoConditionDao digitalCollectionProductInfoConditionDao;


    private final DigitalCollectionProductInfoSubscribeWinBallotDao digitalCollectionProductInfoSubscribeWinBallotDao;

    private final UserCreatorInfoDao userCreatorInfoDao;

    @Override
    public CreateOrderVO findOrderByOrderNo(String orderNo) {
        Order order = orderDao.getByOrderNo(orderNo);

        verificationOrder(order);

        return getCreateOrderVO(order, Boolean.TRUE);
    }

    @Override
    public Page<OrderDTO> orderPageForAdmin(String firstTitle, String phone, String orderNo, String productUuId, OrderStatusEnum status, Date startOrderTime, Date endOrderTime, Date startPayTime, Date endPayTime, int pageNo, int pageSize) {
        Long userId = null;
        if (StrUtil.isNotBlank(phone)) {
            UserInfo userInfo = userInfoDao.getOneByUserTel(phone);
            if (ObjectUtil.isNull(userInfo)) {
                return new Page<>(pageNo, pageSize);
            } else {
                userId = userInfo.getId();
            }
        }
        Long productId = null;
        if (ObjectUtil.isNotEmpty(productUuId)) {
            DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getByProductUuId(productUuId);
            productId = digitalCollectionProductInfo.getId();
        }
        return orderDao.orderDTOPageForAdmin(firstTitle, userId, orderNo, productId, status, startOrderTime, endOrderTime, startPayTime, endPayTime, pageNo, pageSize);
    }

    @Override
    public List<OrderSimpleVO> orderExport(Long productId) {
        return orderDao.orderExport(productId);
    }

    @Override
    public List<OrderDetailListVO> orderDetailExport(Long productId, Date payTimeFrom, Date payTimeTo) {
        return orderDao.orderDetailExport(productId, payTimeFrom, payTimeTo);
    }

    @Override
    public OrderDetailsVO getOrderDetailsById(Long id) {

        OrderDetailsDTO orderDetailsDTO = orderDao.getOrderDetailsById(id);
        int status = orderDetailsDTO.getStatus();
        DigitalCollectionProductInfo product = digitalCollectionProductInfoDao.getProductById(orderDetailsDTO.getProductId());

        OrderDetailsVO orderDetailsVO = BeanUtil.toBean(orderDetailsDTO, OrderDetailsVO.class);
        UserCreatorInfo userCreatorInfo = userCreatorInfoDao.getById(product.getUserCreatorId());
        orderDetailsVO.setNickName(ObjectUtil.isNotNull(userCreatorInfo) ? userCreatorInfo.getDaoName() : null);
        if (OrderStatusEnum.CLOSE.getCode() == status) {
            orderDetailsVO.setOrderStatus("未支付");
            orderDetailsVO.setPayMethod("超时结束");

        } else if (OrderStatusEnum.WAIT_PAY.getCode() == status) {
            orderDetailsVO.setOrderStatus("未支付");
            orderDetailsVO.setPayMethod("未选择");

        } else if (OrderStatusEnum.PAYMENT.getCode() == status) {
            orderDetailsVO.setOrderStatus("已完成");
            orderDetailsVO.setPayMethod(PayMethodEnum.getValue(orderDetailsDTO.getPayType()));
        }

        return orderDetailsVO;
    }

    @Override
    public Boolean getOrderStatus(String orderNo) {
        return ObjectUtil.isNotNull(orderDao.getOrderStatus(orderNo));
    }

    @Override
    public GetTotalPriceVO getTotalPrice(Long productId, String productCount) {

        DigitalCollectionProductInfo digitalCollectionProductInfo = (DigitalCollectionProductInfo) new DigitalCollectionProductInfo().selectById(productId);
        if (ObjectUtil.isEmpty(digitalCollectionProductInfo)) {
            throw new GlobalRunTimeException(ErrorCode.PARAM_ERROR);
        }

        UserInfo user = UserPool.getUser();
        // 默认折扣.
        BigDecimal minDiscount = BigDecimal.ONE;
        if (BeanUtil.isNotEmpty(user)) {
            minDiscount = getMinDiscount(user.getId(), productId);
        }

        BigDecimal productNum = digitalCollectionProductInfo.getProductNum();
        BigDecimal bigDecimal = productNum.multiply(new BigDecimal(productCount)).multiply(minDiscount).setScale(2, BigDecimal.ROUND_DOWN);
        GetTotalPriceVO getTotalPriceVO = new GetTotalPriceVO();
        getTotalPriceVO.setTotalPrice(bigDecimal.toPlainString());

        String equityPropsName = "";
        Integer equityPropsNum = 0;
        Integer equityPropsHaveNum = 0;
        Long equityPropsId = digitalCollectionProductInfo.getEquityPropsId();
        if (ObjectUtil.isNotNull(equityPropsId) && equityPropsId.intValue() > 0) {
            //权益道具数量和记录
            equityPropsName = equityPropsService.getById(digitalCollectionProductInfo.getEquityPropsId()).getFirstTitle();
            equityPropsNum = digitalCollectionProductInfo.getEquityPropsNum();
            if (BeanUtil.isNotEmpty(user)) {
                equityPropsHaveNum = userEquityPropsService.getHavingCountByUserId(digitalCollectionProductInfo.getEquityPropsId(), user.getId());
            }

            equityPropsNum = equityPropsNum * Convert.toInt(productCount);
        }

        getTotalPriceVO.setEquityPropsName(equityPropsName);
        getTotalPriceVO.setEquityPropsNum(equityPropsNum);
        //查询用户持有的数量
        getTotalPriceVO.setEquityPropsHaveNum(equityPropsHaveNum);
        return getTotalPriceVO;
    }

    @Override
    public Integer findLimitBetween(Long start, Long end, Long orderId, Integer collectionId) {
        return orderDao.findLimitBetween(start, end, orderId, collectionId);
    }

    @Override
    public TradingTrendVO tradingTrend(Long id) {
        // 先验证缓存中存不存在
        String key = RedisKeyEnum.TRADING_TREND.getKey() + id;
        if (redisTemplate.hasKey(key)) {
            // 存在直接反序列化返回去
            return JSONObject.parseObject(redisTemplate.opsForValue().get(key).toString(), TradingTrendVO.class);
        }
        // 获取地板价
        SecondCollectionConfig secondCollectionConfig = secondCollectionConfigDao.getByCollectionId(id);
        // 获取最大今日最高价和最低价.如果是空的话则为0
        TodaySHighAndLowPricesVO todaySHighAndLowPricesVO = secondOrderDao.todaySHighAndLowPrices(id);
        TradingTrendVO tradingTrendVO = new TradingTrendVO();
        // 最新成交价
        tradingTrendVO.setLatestTransactionPrice(secondOrderDao.latestTransactionPrice(id));
        if (BeanUtil.isEmpty(todaySHighAndLowPricesVO)) {
            tradingTrendVO.setTodaySHighest(BigDecimal.ZERO);
            tradingTrendVO.setTodaySLowest(BigDecimal.ZERO);
        } else {
            tradingTrendVO.setTodaySHighest(todaySHighAndLowPricesVO.getMaxBuyPrice());
            tradingTrendVO.setTodaySLowest(todaySHighAndLowPricesVO.getMinBuyPrice());
        }
        if (BeanUtil.isEmpty(secondCollectionConfig)) {
            tradingTrendVO.setPriceFloor(BigDecimal.ZERO);
        } else {
            tradingTrendVO.setPriceFloor(secondCollectionConfig.getStartPrice());
        }
        tradingTrendVO.setTurnover(secondOrderDao.dailyTurnover(id));
        // 没有的话就写入到缓存里面,30分钟删除一次.同时交易的时候在发送mq中,进行一次消费,对这个key进行维护
        redisTemplate.opsForValue().set(key, JSONObject.toJSONString(tradingTrendVO), 10 * 60, TimeUnit.SECONDS);
        return tradingTrendVO;
    }

    @Override
    public TradingTrendVO tradingTrendForConsensus(Long id) {
        // 先验证缓存中存不存在
        String key = RedisKeyEnum.TRADING_CONSENSUS_TREND.getKey() + id;
        if (redisTemplate.hasKey(key)) {
            // 存在直接反序列化返回去
            return JSONObject.parseObject(redisTemplate.opsForValue().get(key).toString(), TradingTrendVO.class);
        }
        // 获取地板价
        SecondCollectionConfig secondCollectionConfig = secondCollectionConfigDao.getByCollectionId(id);
        // 获取最大今日最高价和最低价.如果是空的话则为0
        TodaySHighAndLowPricesVO todaySHighAndLowPricesVO = secondOrderDao.todaySHighAndLowPricesForConsensus(id);
        TradingTrendVO tradingTrendVO = new TradingTrendVO();
        // 最新成交价
        tradingTrendVO.setLatestTransactionPrice(secondOrderDao.latestTransactionPriceForConsensus(id));
        if (BeanUtil.isEmpty(todaySHighAndLowPricesVO)) {
            tradingTrendVO.setTodaySHighest(BigDecimal.ZERO);
            tradingTrendVO.setTodaySLowest(BigDecimal.ZERO);
        } else {
            tradingTrendVO.setTodaySHighest(todaySHighAndLowPricesVO.getMaxBuyPrice());
            tradingTrendVO.setTodaySLowest(todaySHighAndLowPricesVO.getMinBuyPrice());
        }
        if (BeanUtil.isEmpty(secondCollectionConfig)) {
            tradingTrendVO.setPriceFloor(BigDecimal.ZERO);
        } else {
            tradingTrendVO.setPriceFloor(secondCollectionConfig.getStartPrice());
        }
        tradingTrendVO.setTurnover(secondOrderDao.dailyTurnoverForConsensus(id));
        // 没有的话就写入到缓存里面,30分钟删除一次.同时交易的时候在发送mq中,进行一次消费,对这个key进行维护
        redisTemplate.opsForValue().set(key, JSONObject.toJSONString(tradingTrendVO), 10 * 60, TimeUnit.SECONDS);
        return tradingTrendVO;
    }

    @Override
    public TradingTrendVO tradingTrendNotInConsensus(Long id) {
        // 先验证缓存中存不存在
        String key = RedisKeyEnum.TRADING_CONSENSUS_TREND.getKey() + id;
        if (redisTemplate.hasKey(key)) {
            // 存在直接反序列化返回去
            return JSONObject.parseObject(redisTemplate.opsForValue().get(key).toString(), TradingTrendVO.class);
        }
        // 获取地板价
        SecondCollectionConfig secondCollectionConfig = secondCollectionConfigDao.getByCollectionId(id);
        // 获取最大今日最高价和最低价.如果是空的话则为0
        TodaySHighAndLowPricesVO todaySHighAndLowPricesVO = secondOrderDao.todaySHighAndLowPricesNotInConsensus(id);
        TradingTrendVO tradingTrendVO = new TradingTrendVO();
        // 最新成交价
        tradingTrendVO.setLatestTransactionPrice(secondOrderDao.latestTransactionPriceNotInConsensus(id));
        if (BeanUtil.isEmpty(todaySHighAndLowPricesVO)) {
            tradingTrendVO.setTodaySHighest(BigDecimal.ZERO);
            tradingTrendVO.setTodaySLowest(BigDecimal.ZERO);
        } else {
            tradingTrendVO.setTodaySHighest(todaySHighAndLowPricesVO.getMaxBuyPrice());
            tradingTrendVO.setTodaySLowest(todaySHighAndLowPricesVO.getMinBuyPrice());
        }
        if (BeanUtil.isEmpty(secondCollectionConfig)) {
            tradingTrendVO.setPriceFloor(BigDecimal.ZERO);
        } else {
            tradingTrendVO.setPriceFloor(secondCollectionConfig.getStartPrice());
        }
        tradingTrendVO.setTurnover(secondOrderDao.dailyTurnoverNotInConsensus(id));
        // 没有的话就写入到缓存里面,30分钟删除一次.同时交易的时候在发送mq中,进行一次消费,对这个key进行维护
        redisTemplate.opsForValue().set(key, JSONObject.toJSONString(tradingTrendVO), 10 * 60, TimeUnit.SECONDS);
        return tradingTrendVO;
    }

    @Override
    public Page<FlowRecordVO> flowRecord(FlowRecordDTO flowRecordDTO) {
        return secondOrderDao.flowRecord(flowRecordDTO);
    }

    @Override
    public Page<FlowRecordVO> flowRecordForConsensus(FlowRecordDTO flowRecordDTO) {
        return secondOrderDao.flowRecordForConsensus(flowRecordDTO);
    }

    @Override
    public Page<FlowRecordVO> flowRecordNotInConsensus(FlowRecordDTO flowRecordDTO) {
        return secondOrderDao.flowRecordNotInConsensus(flowRecordDTO);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiveFreeCollection(UserInfo userInfo, Long productId, Integer count) {
        String key = RedisKeyEnum.FREE_COLLECTION_RECEIVE.getKey() + productId;
        RLock lock = redisson.getLock(key);
        try {
            boolean res = lock.tryLock(3, TimeUnit.SECONDS);
            if (res) {
                DigitalCollectionProductInfo product = digitalCollectionProductInfoDao.getById(productId);
                Assert.isTrue(ObjectUtil.isNotNull(product) && product.getCommodityType() == CommodityType.LOTTERY, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND));
                Assert.isTrue(userInfo.getIsSm(), () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
                DateTime now = DateTime.now();
                Assert.isTrue(now.isAfter(product.getBeginTime()), () -> new GlobalRunTimeException("活动尚未开始"));
                Assert.isTrue(now.isBefore(product.getEndTime()), () -> new GlobalRunTimeException("活动尚未开始"));


                DigitalCollection collection = digitalCollectionDao.getById(product.getRelationId());
                //校验是否售罄
                Assert.isTrue(!product.getIsSoldOut(), () -> new GlobalRunTimeException("商品已售罄"));
                //校验库存
                ProductStock productStock = productStockService.getProductStock(product.getId(), null, null);
                Assert.isTrue(ObjectUtil.isNotNull(productStock) && productStock.getUsableCount() >= count, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_IS_SOLD_OUT));

                //校验是否已经领取
                Assert.isFalse(receiveProductRecordDao.getReceivedCount(productId, userInfo.getId()) + count > product.getUpperLimit(), () -> new GlobalRunTimeException(ErrorCode.EVENT_ACQUISITION_HAS_REACHED_THE_UPPER_LIMIT));

                //减库存
                Assert.isTrue(productStockService.deductStock(product.getId(), product.getRelationId(), count, userInfo.getId(), CommodityType.LOTTERY), () -> new GlobalRunTimeException(ErrorCode.THE_SYSTEM_IS_BUSY_PLEASE_TRY_AGAIN_LATER));

                //添加活动记录
                for (int i = 0; i < count; i++) {
                    //给用户添加藏品
                    UserCollection userCollection = userCollectionService.addCollection(userInfo.getId(), null, collection.getId(), IdUtil.getSnowflakeNextIdStr(), product.getCreationContent(), collection.getLevel(), collection.getFirstTitle(), product.getUserCreatorId(), ReceivedCollectionType.ACTIVITY, null, null, null, Boolean.TRUE, product.getId(), 0L, 0L, BigDecimal.ZERO, 0, null, null, AddCollectionEnum.STAIR, null, null, false);
                    ReceiveProductRecord receiveProductRecord = new ReceiveProductRecord();
                    receiveProductRecord.setUserId(userInfo.getId());
                    receiveProductRecord.setProductId(productId);
                    receiveProductRecord.setCollectionId(userCollection.getCollectionId());
                    receiveProductRecord.setReceiveTime(DateTime.now());
                    receiveProductRecord.setReceiveCount(1);
                    receiveProductRecord.insert();
                    //添加藏品流转记录
                    CollectionCirculatingRecord collectionCirculatingRecord = new CollectionCirculatingRecord();
                    collectionCirculatingRecord.setUserId(userInfo.getId());
                    collectionCirculatingRecord.setCollectionId(collection.getId());
                    collectionCirculatingRecord.setCommodityType(CommodityType.LOTTERY);
                    collectionCirculatingRecord.setTypeClassify(ClassifyType.COLLECTION);
                    collectionCirculatingRecord.setReceivedCollectionType(ReceivedCollectionType.ACTIVITY);
                    collectionCirculatingRecord.setToUserCollection(userCollection.getId());
                    collectionCirculatingRecord.setToUserId(userCollection.getId());
                    collectionCirculatingRecord.setOrderId(0L);
                    collectionCirculatingRecord.setInviteTaskId(0L);
                    collectionCirculatingRecord.setUserReceiveInviteId(0L);
                    collectionCirculatingRecord.setUserReceiveIntegraId(0L);
                    collectionCirculatingRecord.setAirdropGrantRecordId(0L);
                    collectionCirculatingRecord.setUserSynthesisRecordId(0L);
                    collectionCirculatingRecord.setNumber(userCollection.getNumbering());
                    collectionCirculatingRecord.insert();
                }
                if (product.getTypeClassify() == ClassifyType.COLLECTION && collection.getCollectionType() == DigitalMarketTypeEnum.ECOLOGY) {
                    userConsensusService.adjustConsensusService(userInfo.getId(), collection.getId(), BigDecimal.valueOf(count), UserConsensusTypeEnums.FREE, collection.getFirstTitle(), null);
                }
            } else {
                throw new GlobalRunTimeException(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            throw new GlobalRunTimeException("当前人数过多，请稍后再试");
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Integer orderCount(Long userId) {
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getUserId, userId);
        wrapper.eq(Order::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.last(" limit 5");
        return orderDao.list(wrapper).size();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CreateOrderVO createOrder(Long productId, Integer count, List<OrderFirstPayDTO> firstPayDTOs, List<OrderRushPayDTO> rushBuyDTOs) throws GlobalException {
        UserInfo userInfo = UserPool.getUser();
        DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getById(productId);
        Assert.notNull(digitalCollectionProductInfo, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND));

        Integer type = verificationProduct(digitalCollectionProductInfo, userInfo, count, firstPayDTOs, rushBuyDTOs);//检查商品
        //校验虚拟商品
        Long equityPropsId = digitalCollectionProductInfo.getEquityPropsId();

        String userEquityPropsIds = null;
        String equityPropsName = "";
        Integer orderEquityPropsNum = 0;
        // 如果不是申购的话,才会走下面的,申购的不走.已经使用过了道具卡了.
        if (digitalCollectionProductInfo.getCommodityType() != CommodityType.SUBSCRIBE_COMMODITY) {
            //是否配置了权益商品
            if (ObjectUtil.isNotNull(equityPropsId) && equityPropsId > 0) {
                //校验是否有权益商品
                EquityProps equityProps = equityPropsService.getById(equityPropsId);
                Assert.notNull(equityProps, () -> new GlobalException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST));
                //持有数量
                Integer havingCount = userEquityPropsService.getHavingCountByUserId(equityPropsId, userInfo.getId());

                Integer equityPropsNum = digitalCollectionProductInfo.getEquityPropsNum();
                //所需要的权益商品数量
                Integer sumEquityPropsNum = equityPropsNum * count;
                //校验是否有足够的权益商品
                Assert.isTrue(havingCount >= sumEquityPropsNum, () -> new GlobalException(ErrorCode.EQUITY_PROPS_NOT_ENOUGH));

                List<UserEquityProps> list = userEquityPropsService.getHavingListByUserIdAndEquityPropsIdAndLimit(userInfo.getId(), equityPropsId, sumEquityPropsNum);
                //校验是否有足够的权益商品
                Assert.isTrue(list.size() >= sumEquityPropsNum, () -> new GlobalException(ErrorCode.EQUITY_PROPS_NOT_ENOUGH));
                //扣除权益商品
                Assert.isTrue(userEquityPropsService.updateBatchById(list), () -> new GlobalException(ErrorCode.FAILED_TO_OBTAIN_EQUITY_PROPS));

                userEquityPropsIds = list.stream().map(UserEquityProps::getId).map(String::valueOf).collect(Collectors.joining(","));
                orderEquityPropsNum = sumEquityPropsNum;
                equityPropsName = equityProps.getFirstTitle();
            }
        }
        productStockService.frozenCount(digitalCollectionProductInfo.getId(), digitalCollectionProductInfo.getRelationId(), count);
        Order order = new Order();
        order.setProductId(digitalCollectionProductInfo.getId());
        order.setFirstTitle(digitalCollectionProductInfo.getFirstTitle());
        order.setImageUrl(digitalCollectionProductInfo.getCreationContent());
        order.setRelationId(digitalCollectionProductInfo.getRelationId());
        order.setStatus(OrderStatusEnum.WAIT_PAY);
        order.setOrderNo(OrderNoUtil.getOrderNo());
        order.setCount(count);
        order.setShareProfitPanelId(digitalCollectionProductInfo.getShareProfitPanelId());
        order.setUserCreatorId(digitalCollectionProductInfo.getUserCreatorId());
        order.setTypeClassify(digitalCollectionProductInfo.getTypeClassify());
        order.setOrderType(digitalCollectionProductInfo.getCommodityType());
        order.setOrderTime(DateTime.now());
        DateTime offset = DateTime.now().offset(DateField.MINUTE, 5);
        order.setCloseTime(offset);
        order.setUserId(UserPool.getUser().getId());
        order.setAppleProductId(digitalCollectionProductInfo.getAppleProductId());
        order.setUserEquityPropsIds(userEquityPropsIds);
        order.setEquityPropsName(equityPropsName);
        order.setEquityPropsNum(orderEquityPropsNum);
        BigDecimal minDiscount = getMinDiscount(userInfo.getId(), productId);
        BigDecimal productPrice = digitalCollectionProductInfo.getProductNum().multiply(BigDecimal.valueOf(count)).multiply(minDiscount).setScale(2, BigDecimal.ROUND_DOWN);
        order.setProductPrice(productPrice);
        // 2022年11月7日18:25:43新增字段,标明该商品原价格
        order.setOriginalPrice(digitalCollectionProductInfo.getProductNum().multiply(BigDecimal.valueOf(count)));
        order.setSettleFlag(!filterIncomeListService.getIsTeamIncomeByUserId(userInfo.getId()));
        order.setPerformanceSettleFlag(order.getSettleFlag());


        //折扣小于1
        if (minDiscount.compareTo(new BigDecimal("1")) == -1) {
            order.setIsDiscount(Boolean.TRUE);
            order.setDiscountPrice(minDiscount);
        }
        // 是否是优先购买
        if (type == 0) {
            order.setIsBuyFirst(Boolean.FALSE);
            order.setIsRushBuy(Boolean.FALSE);
        } else if (type == 1) {
            order.setIsBuyFirst(Boolean.TRUE);
            order.setIsRushBuy(Boolean.FALSE);
        } else if (type == 2) {
            order.setIsBuyFirst(Boolean.FALSE);
            order.setIsRushBuy(Boolean.TRUE);
        }
        order.insert();

        // 处理申购商品,购买数量 锁的中签数量的处理判定.
        if (digitalCollectionProductInfo.getCommodityType() == CommodityType.SUBSCRIBE_COMMODITY) {
            // 扣除对应的签数.并且把对应的订单id写入到中签表中,用来对应订单
            Boolean b = digitalCollectionProductInfoSubscribeWinBallotDao.freezeTheSubscriptionCode(digitalCollectionProductInfo.getId(), userInfo.getId(), count, order.getId());
            if (!b) {
                throw new GlobalRunTimeException("申购码不足");
            }
            // 购买的时候必须持有指定的藏品
            DigitalCollectionProductInfoSubscribe digitalCollectionProductInfoSubscribe = digitalCollectionProductInfoSubscribeDao.getByProductInfoSubscribe(digitalCollectionProductInfo.getId());
            if (ObjectUtil.isNotNull(digitalCollectionProductInfoSubscribe)) {
                if (digitalCollectionProductInfoSubscribe.getParticipationCondition()) {
                    List<DigitalCollectionProductInfoCondition> digitalCollectionProductInfoConditionBatchByProductId = digitalCollectionProductInfoConditionDao.getDigitalCollectionProductInfoConditionBatchByProductId(digitalCollectionProductInfoSubscribe.getProductId());
                    if (digitalCollectionProductInfoSubscribe.getConditionType() == ProductInfoSubscribeEnum.OR) {
                        Integer userHoldCollectionByIds = userCollectionDao.getUserHoldCollectionByIds(userInfo.getId(), digitalCollectionProductInfoConditionBatchByProductId.stream().map(DigitalCollectionProductInfoCondition::getCollectionId).collect(Collectors.toList()));
                        if (userHoldCollectionByIds <= 0) {
                            throw new GlobalRunTimeException("购买失败,请先持有指定藏品");
                        }
                    } else if (digitalCollectionProductInfoSubscribe.getConditionType() == ProductInfoSubscribeEnum.ALL) {
                        List<Long> collect = digitalCollectionProductInfoConditionBatchByProductId.stream().map(DigitalCollectionProductInfoCondition::getCollectionId).collect(Collectors.toList());
                        collect.forEach(collectionId -> {
                            List list = new ArrayList();
                            list.add(collectionId);
                            Integer userHoldCollectionByIds = userCollectionDao.getUserHoldCollectionByIds(userInfo.getId(), list);
                            if (userHoldCollectionByIds <= 0) {
                                throw new GlobalRunTimeException("购买失败,请先持有指定藏品");
                            }
                        });

                    }
                }
            }


        }
        //优先购
        if (order.getIsBuyFirst()) {
            for (OrderFirstPayDTO firstPayDTO : firstPayDTOs) {
                OrderFirstBuy orderFirstBuy = new OrderFirstBuy();
                orderFirstBuy.setBuyCount(firstPayDTO.getCount());
                orderFirstBuy.setOrderId(order.getId());
                orderFirstBuy.setType(firstPayDTO.getType());
                if (firstPayDTO.getType().intValue() < 2) {
                    orderFirstBuy.setCollectionUuid(firstPayDTO.getCollectionUuid());
                }
                orderFirstBuy.insert();
            }
        }
        //优先抢
        if (order.getIsRushBuy()) {
            for (OrderRushPayDTO rushBuyDTO : rushBuyDTOs) {
                OrderRushBuy orderRushBuy = new OrderRushBuy();
                orderRushBuy.setBuyCount(rushBuyDTO.getCount());
                orderRushBuy.setOrderId(order.getId());
                orderRushBuy.setType(rushBuyDTO.getType());
                if (orderRushBuy.getType().intValue() < 2) {
                    orderRushBuy.setCollectionUuid(rushBuyDTO.getCollectionUuid());
                }
                orderRushBuy.insert();
            }
        }
        return getCreateOrderVO(order, Boolean.FALSE);
    }

    @Override
    public CreateOrderVO createRoughStoneOrder(UserInfo userInfo, Long productId, Integer count) throws GlobalException {
        DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getById(productId);

        Integer userHoldCount = userCollectionDao.getHoldCountByCollectionId(digitalCollectionProductInfo.getRelationId(), userInfo.getId());
        Assert.isTrue(userHoldCount + count <= digitalCollectionProductInfo.getUpperLimit(), () -> new GlobalException("超出持有上限"));
        //校验用户
        Assert.isTrue(userInfo.getIsSm(), () -> new GlobalException(ErrorCode.USER_NOT_SM));
        //校验商品
        Assert.notNull(digitalCollectionProductInfo, () -> new GlobalException(ErrorCode.PRODUCT_NOT_FOUND));
        //校验商品状态
        Assert.isTrue(digitalCollectionProductInfo.getStatus(), () -> new GlobalException(ErrorCode.PRODUCT_HAS_BEEN_DESCONTINUED));
        //校验是否售罄
        Assert.isFalse(digitalCollectionProductInfo.getIsSoldOut(), () -> new GlobalException(ErrorCode.COLLECTION_IS_SOLD_OUT));

        Assert.isTrue(digitalCollectionProductInfo.getCommodityType() == CommodityType.SALVAGE_COLLECTION, () -> new GlobalException("商品类型不正确"));

        //校验是否有未付款的订单
        RoughStoneOrder roughStoneOrder = roughStoneOrderDao.getOrderByProductAndUserId(userInfo.getId(), digitalCollectionProductInfo.getId());
        Assert.isFalse(ObjectUtil.isNotNull(roughStoneOrder) && roughStoneOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.WAIT_PAY_ORDER));

        //校验库存(剩余库存量 > 购买量)
        ProductStock productStock;
        switch (digitalCollectionProductInfo.getTypeClassify()) {
            case COLLECTION:
                productStock = productStockService.getProductStock(digitalCollectionProductInfo.getId(), null, null);
                break;
            case BLIND_BOX:
                throw new GlobalException("商品类型不正确");
            default:
                throw new GlobalException(ErrorCode.COLLECTION_IS_SOLD_OUT);
        }
        Assert.isTrue(ObjectUtil.isNotNull(productStock) && productStock.getUsableCount() >= count, () -> new GlobalException("剩余库存不足"));
        productStockService.frozenCount(digitalCollectionProductInfo.getId(), digitalCollectionProductInfo.getRelationId(), count);
        RoughStoneOrder order = new RoughStoneOrder();
        order.setProductId(digitalCollectionProductInfo.getId());
        order.setFirstTitle(digitalCollectionProductInfo.getFirstTitle());
        order.setImageUrl(digitalCollectionProductInfo.getCreationContent());
        order.setCollectionId(digitalCollectionProductInfo.getRelationId());
        order.setStatus(OrderStatusEnum.WAIT_PAY);
        order.setOrderNo(OrderNoUtil.getOrderNo());
        order.setCount(count);
        order.setTypeClassify(digitalCollectionProductInfo.getTypeClassify());
        order.setOrderTime(DateTime.now());
        DateTime offset = DateTime.now().offset(DateField.HOUR, 1);
        order.setCloseTime(offset);
        order.setUserId(UserPool.getUser().getId());

        BigDecimal productPrice = digitalCollectionProductInfo.getProductNum().multiply(BigDecimal.valueOf(count)).setScale(2, BigDecimal.ROUND_DOWN);
        order.setProductPrice(productPrice);
        order.insert();
        CreateOrderVO createOrderVO = new CreateOrderVO();
        createOrderVO.setOrderId(order.getId());
        createOrderVO.setOffsetTime(order.getCloseTime().getTime() - SystemClock.now());
        createOrderVO.setProductNum(order.getProductPrice().stripTrailingZeros().toPlainString());
        createOrderVO.setOrderNo(order.getOrderNo());
        createOrderVO.setNowDate(DateUtil.now());
        createOrderVO.setExpirationTime(order.getCloseTime());
        createOrderVO.setPurchaseNotes(staticDataDao.getByType("purchase_notes").getValue());
        return createOrderVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeOrder(Long id) throws GlobalException {
        Order order = orderDao.getById(id);
        if (ObjectUtil.isEmpty(order)) {
            throw new GlobalException(ErrorCode.ORDER_NOT_FOUND);
        }
//        Assert.isNull(order, ()->new GlobalException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getUserId().longValue() == UserPool.getUser().getId().longValue(), () -> new GlobalException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isFalse(order.getStatus() == OrderStatusEnum.PAYMENT, () -> new GlobalException(ErrorCode.ORDER_PAID));
        if (order.getStatus() == OrderStatusEnum.CLOSE) {
            throw new GlobalException(ErrorCode.ORDER_CLOSED);
        }
        Assert.isTrue(orderDao.closeOrder(id), () -> new GlobalRunTimeException("关闭订单失败"));
        DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getById(order.getProductId());
        if (digitalCollectionProductInfo.getCommodityType() == CommodityType.SUBSCRIBE_COMMODITY) {
            // 申购商品的申购码消耗掉.
            Assert.isTrue(digitalCollectionProductInfoSubscribeWinBallotDao.releaseApplicationCode(order.getProductId(), order.getUserId(), order.getId()), () -> new GlobalRunTimeException(ErrorCode.SUBSCRIPTION_CODE_CONVERSION));
        } else {
            String userEquityPropsIds = order.getUserEquityPropsIds();
            if (StrUtil.isNotBlank(userEquityPropsIds)) {
                userEquityPropsService.freezePropsToNormalByIds(userEquityPropsIds, order.getUserId());
            }
        }

        productStockService.SubFrozenCount(order.getProductId(), order.getRelationId(), order.getCount());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoCloseOrder(Order order) throws GlobalException {
//        order = orderDao.getById(order.getId());
//        if(order.getStatus()!=OrderStatusEnum.WAIT_PAY){
//            return;
//        }
        DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getById(order.getProductId());
        if (digitalCollectionProductInfo.getCommodityType() == CommodityType.SUBSCRIBE_COMMODITY) {
            // 申购商品的申购码消耗掉.
            Assert.isTrue(digitalCollectionProductInfoSubscribeWinBallotDao.releaseApplicationCode(order.getProductId(), order.getUserId(), order.getId()), () -> new GlobalRunTimeException(ErrorCode.SUBSCRIPTION_CODE_CONVERSION));
        } else {
            String userEquityPropsIds = order.getUserEquityPropsIds();
            if (StrUtil.isNotBlank(userEquityPropsIds)) {
                userEquityPropsService.freezePropsToNormalByIds(userEquityPropsIds, order.getUserId());
            }
        }
        Assert.isTrue(orderDao.closeOrder(order.getId()), () -> new GlobalRunTimeException("关闭订单失败"));
        productStockService.SubFrozenCount(order.getProductId(), order.getRelationId(), order.getCount());
    }

    @Override
    public List<Order> getCloseOrder() {
        return orderDao.getCloseOrder();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(String orderNo) {
        Order order = orderDao.getByOrderNo(orderNo);
        DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getById(order.getProductId());
        if (ObjectUtil.isNull(order) || order.getStatus() != OrderStatusEnum.WAIT_PAY) {
            throw new GlobalRunTimeException("未找到对应订单");
        }
        DateTime now = DateTime.now();
        order.setPayTime(now);
        order.setStatus(OrderStatusEnum.PAYMENT);
        order.updateById();

        if (digitalCollectionProductInfo.getCommodityType() == CommodityType.SUBSCRIBE_COMMODITY) {
            // 申购商品的申购码消耗掉.
            Assert.isTrue(digitalCollectionProductInfoSubscribeWinBallotDao.updateTheSubscriptionCode(order.getProductId(), order.getUserId(), order.getId()), () -> new GlobalRunTimeException(ErrorCode.SUBSCRIPTION_CODE_CONVERSION));
        } else {
            if (ObjectUtil.isNotNull(order.getUserEquityPropsIds()) && order.getUserEquityPropsIds().length() > 0) {
                //把冻结的权益商品消耗掉
                Assert.isTrue(userEquityPropsService.freezePropsToUseByIds(order.getUserEquityPropsIds(), order.getUserId(), order.getEquityPropsNum(), "购买" + order.getFirstTitle(), order.getId()), () -> new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_CONVERSION_FAILED));
            }
        }

        productStockService.subStock(order.getProductId(), order.getRelationId(), order.getCount(), order.getUserId(), CommodityType.PRODUCT);
        boolean isOpen = false;
        Long boxId = null;
        String boxTitle = null;
        String boxImage = null;
        Long collectionId = null;
        DigitalCollection digitalCollection = null;

        for (int i = 0; i < order.getCount(); i++) {
            switch (order.getTypeClassify()) {
                case COLLECTION:
                    collectionId = order.getRelationId();
                    digitalCollection = digitalCollectionDao.getById(collectionId);
                    isOpen = true;
                    break;
                case BLIND_BOX:
                    BoxItem boxItem = boxItemService.openBox(order.getProductId(), order.getRelationId());
                    collectionId = boxItem.getCollectionId();
                    digitalCollection = digitalCollectionDao.getById(collectionId);
                    productStockService.subItemStock(order.getProductId(), order.getRelationId(), boxItem.getId(), 1, order.getUserId(), CommodityType.PRODUCT);
                    BoxProduct boxProduct = boxProductDao.getById(order.getRelationId());
                    boxId = boxProduct.getId();
                    boxTitle = boxProduct.getFirstTitle();
                    boxImage = order.getImageUrl();
                    isOpen = false;
                    break;
            }
            UserCollection userCollection = userCollectionService.addCollection(order.getUserId(), null, digitalCollection.getId(), IdUtil.getSnowflakeNextIdStr(), digitalCollection.getCreationContent(), digitalCollection.getLevel(), digitalCollection.getFirstTitle(), digitalCollection.getUserCreatorId(), ReceivedCollectionType.BUY, boxId, boxTitle, boxImage, isOpen, order.getProductId(), order.getId(), 0L, order.getOriginalPrice().divide(BigDecimal.valueOf(order.getCount())), 0, null, null, AddCollectionEnum.STAIR, null, null, false);
            //藏品流转表记录
            CollectionCirculatingRecord collectionCirculatingRecord = new CollectionCirculatingRecord();
            collectionCirculatingRecord.setUserId(order.getUserId());
            collectionCirculatingRecord.setCollectionId(digitalCollection.getId());
            collectionCirculatingRecord.setCommodityType(CommodityType.PRODUCT);
            collectionCirculatingRecord.setTypeClassify(order.getTypeClassify());
            collectionCirculatingRecord.setReceivedCollectionType(ReceivedCollectionType.BUY);
            collectionCirculatingRecord.setToUserCollection(userCollection.getId());
            collectionCirculatingRecord.setOrderId(order.getId());
            collectionCirculatingRecord.insert();
        }
        if (order.getTypeClassify() == ClassifyType.COLLECTION && digitalCollection.getCollectionType() == DigitalMarketTypeEnum.ECOLOGY) {
            userConsensusService.adjustConsensusService(order.getUserId(), digitalCollection.getId(), BigDecimal.valueOf(order.getCount()), UserConsensusTypeEnums.BUY, digitalCollection.getFirstTitle(), null);
        }


        if (order.getIsBuyFirst()) {
            List<OrderFirstBuy> list = orderFirstBuyDao.getByOrderId(order.getId());
            for (OrderFirstBuy orderFirstBuy : list) {
                FirstBuyRecord firstBuyRecord = new FirstBuyRecord();
                firstBuyRecord.setProductId(order.getProductId());
                firstBuyRecord.setUserId(order.getUserId());
                firstBuyRecord.setCollectionUuid(orderFirstBuy.getCollectionUuid());
                firstBuyRecord.setType(orderFirstBuy.getType());
                firstBuyRecord.setBuyCount(orderFirstBuy.getBuyCount());
                firstBuyRecord.insert();
                if (StrUtil.isNotBlank(orderFirstBuy.getCollectionUuid())) {
                    for (int i = 0; i < orderFirstBuy.getBuyCount(); i++) {
                        PrivilegeUseLog privilegeUseLog = new PrivilegeUseLog();
                        privilegeUseLog.setCollectionUuid(orderFirstBuy.getCollectionUuid());
                        privilegeUseLog.setOrderTime(now);
                        privilegeUseLog.setOrderId(order.getId());
                        privilegeUseLog.setRecordMonth(now.toString("yyyyMM"));
                        privilegeUseLog.insert();
                    }
                }
            }
        } else if (order.getIsRushBuy()) {
            List<OrderRushBuy> list = orderRushBuyDao.getByOrderId(order.getId());
            for (OrderRushBuy orderRushBuy : list) {
                RushBuyRecord rushBuyRecord = new RushBuyRecord();
                rushBuyRecord.setProductId(order.getProductId());
                rushBuyRecord.setUserId(order.getUserId());
                rushBuyRecord.setCollectionUuid(orderRushBuy.getCollectionUuid());
                rushBuyRecord.setType(orderRushBuy.getType());
                rushBuyRecord.setBuyCount(orderRushBuy.getBuyCount());
                rushBuyRecord.insert();
            }
        }
        //账单明细记录
        UserWallet userWallet = userWalletDao.getByUserId(order.getUserId());
        ExpenditureRecord expenditureRecord = new ExpenditureRecord();
        expenditureRecord.setUserId(order.getUserId());
        expenditureRecord.setAmount(order.getProductPrice());
        expenditureRecord.setCharge(BigDecimal.ZERO);
        expenditureRecord.setRealAmount(BigDecimal.ZERO);
        expenditureRecord.setType(ExpenditureRecordTypeEnum.EXPENDITURE);
        expenditureRecord.setBeforeBalance(userWallet.getBalance());
        expenditureRecord.setAfterBalance(userWallet.getBalance());
        expenditureRecord.setOrderId(order.getId());
        expenditureRecordDao.insert(expenditureRecord);
        //插入积分完成记录并添加积分
        userReceiveIntegralService.completeSpendIntegralTask(order.getUserId(), IntegralTaskEnum.CONSUMPTION_INTEGRAL, AssetChangeLogEnum.CONSUMPTION_INTEGRAL, order.getProductPrice());
        //修改用户为用效用户
        UserInfo userInfo = userInfoDao.getById(order.getUserId());
        //消费金额增加
        userInfoDao.addHoldToen(order.getProductPrice(), userInfo.getId());

        if (!userInfo.getIsValid()) {
            userInfoDao.setIsValid(userInfo.getId());
            messageQueueHelper.sendMessage(MessageTopic.USER_FIRST_BUY, new UserFirstBuyDTO(userInfo.getId(), order.getId(), 1));
        }
        if (!filterIncomeListDao.getIsContainsUserId(order.getUserId())) {
            messageQueueHelper.sendMessage(MessageTopic.FIRST_LEVEL_DIRECT_PUSH_INCOME, order);
        }
        //发送一级订单成功消息
        messageQueueHelper.sendMessage(MessageTopic.FIRST_ORDER_TOPIC, order);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                MetaMapSettleDTO metaMapSettleDTO = new MetaMapSettleDTO();
                MetaMapSettleDTO metaMapSettle = metaMapSettleDTO.order(order.getOrderNo(), order.getUserId(), MetaMapSettleSourceTypeEnum.FIRST_ORDER, order.getProductPrice(), BigDecimal.ZERO, order.getFirstTitle(), order.getShareProfitPanelId(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                messageQueueHelper.sendMessage(MessageTopic.META_MAP_SETTLE, metaMapSettle, MessageTopic.META_MAP_SETTLE, order.getOrderNo());
            }
        });

    }

    @Override
    public GetPaySignVO getPaySign(Long orderId, PayMethodEnum payMethodEnum) throws GlobalException {
        Order order = orderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalException(ErrorCode.ORDER_NOT_FOUND));
        if (ObjectUtil.isNotNull(order)) {
            Assert.isFalse(order.getStatus() == OrderStatusEnum.CLOSE, () -> new GlobalException(ErrorCode.ALREADY_BUY));
            Assert.isFalse(order.getStatus() == OrderStatusEnum.PAYMENT, () -> new GlobalException(ErrorCode.WAIT_PAY_ORDER));
        }

        BigDecimal productPrice = order.getProductPrice();
        Date closeTime = order.getCloseTime();
        String orderNo = order.getOrderNo();

        String sdkParams = AliPayCore.getSdkParamsMetaGo(orderNo, productPrice.stripTrailingZeros().toEngineeringString(), DateUtil.format(closeTime, "yyyy-MM-dd HH:mm:ss"));

        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setOrderNo(orderNo);
        getPaySignVO.setSign(sdkParams);

        return getPaySignVO;
    }


    @Override
    public Result getAliPayStatusByOrderNo(String orderNo) {

        try {
            Integer rs = AliPayCore.getRsMeTaGo(orderNo);

            if (rs == 3) {
                return Result.fail(ErrorCode.PAYMENT_FAILED);
            } else {
                return Result.success("支付成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return Result.fail(ErrorCode.PAYMENT_FAILED);
        }
    }

    @Override
    public IPage orderPage(OrderStatusEnum orderStatusEnum, ClassifyType orderType, int pageNo, int pageSize) {
        Long userId = UserPool.getUser().getId();
        return orderDao.orderPage(userId, orderStatusEnum, orderType, pageNo, pageSize);
    }

    /**
     * 校验商品信息
     *
     * @param digitalCollectionProductInfo
     */
    private Integer verificationProduct(DigitalCollectionProductInfo digitalCollectionProductInfo, UserInfo userInfo, Integer count, List<OrderFirstPayDTO> firstPayDTOs, List<OrderRushPayDTO> orderRushPayDTOS) throws GlobalException {

        if (digitalCollectionProductInfo.getTypeClassify() == ClassifyType.COLLECTION) {
            DigitalCollection collection = digitalCollectionDao.getById(digitalCollectionProductInfo.getRelationId());
            Assert.notNull(collection, () -> new GlobalRunTimeException("关联藏品不存在"));

            if (collection.getIsUpgrade()) {//如果是升级藏品
                if (userInfo.getLevel() == DaoLevelTypeEnum.CITY_LORD) {//如果是城主
                    //城主购买城主
                    Assert.isFalse(collection.getDaoLevel() == userInfo.getLevel(), () -> new GlobalRunTimeException("藏品购买已达上限"));

                    if (collection.getDaoLevel() == DaoLevelTypeEnum.RESIDENT) {//如果是城主购买居民
                        Assert.isFalse(userCollectionDao.getUpgradeCollectionCountByLevel(userInfo.getId(), DaoLevelTypeEnum.RESIDENT.getCode()), () -> new GlobalRunTimeException("藏品购买已达上限"));
                    }

                } else if (userInfo.getLevel() == DaoLevelTypeEnum.RESIDENT) {//如果是居民 购买居民
                    Assert.isFalse(collection.getDaoLevel() == userInfo.getLevel(), () -> new GlobalRunTimeException("藏品购买已达上限"));
                }
            }
        }

        //校验是否是审核的账户
        if (digitalCollectionProductInfo.getIsIosShow()) {
            Assert.isTrue(userInfo.getUserTel().equals("13849904109") || userInfo.getUserTel().equals("16725719559"), () -> new GlobalException(ErrorCode.PRODUCT_NOT_FOUND));
        }

        Object o = redisTemplate.opsForValue().get(RedisKeyEnum.DEROGATION_OF_POWER.getKey() + userInfo.getId());
        if (o != null) {
            throw new GlobalException("警告：您已被禁止购买商品，请联系客服处理");
        }

        if (digitalCollectionProductInfo.getIsRegisterTime()) {
            Assert.isTrue(userInfo.getCreateTime().after(digitalCollectionProductInfo.getRegisterBeginTime()), () -> new GlobalException("注册时间不符合"));
            Assert.isTrue(userInfo.getCreateTime().before(digitalCollectionProductInfo.getRegisterEndTime()), () -> new GlobalException("注册时间不符合"));
        }

        //0:正常购买 1:优先购 2:优先抢
        Integer type = 0;
        //校验用户
        Assert.isTrue(userInfo.getIsSm(), () -> new GlobalException(ErrorCode.USER_NOT_SM));
        //校验商品
        Assert.notNull(digitalCollectionProductInfo, () -> new GlobalException(ErrorCode.PRODUCT_NOT_FOUND));
        //校验商品状态
        Assert.isTrue(digitalCollectionProductInfo.getStatus(), () -> new GlobalException(ErrorCode.PRODUCT_HAS_BEEN_DESCONTINUED));
        //校验是否售罄
        Assert.isFalse(digitalCollectionProductInfo.getIsSoldOut(), () -> new GlobalException(ErrorCode.COLLECTION_IS_SOLD_OUT));
        //校验是否有未付款的订单
        Order order = orderDao.getOrderByProductAndUserId(userInfo.getId(), digitalCollectionProductInfo.getId());
        Assert.isFalse(ObjectUtil.isNotNull(order) && order.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.WAIT_PAY_ORDER));
        //校验库存(剩余库存量 > 购买量)
        ProductStock productStock;
        switch (digitalCollectionProductInfo.getTypeClassify()) {
            case COLLECTION:
                productStock = productStockService.getProductStock(digitalCollectionProductInfo.getId(), null, null);
                break;
            case BLIND_BOX:
                productStock = productStockService.getProductStock(digitalCollectionProductInfo.getId(), digitalCollectionProductInfo.getRelationId(), null);
                break;
            default:
                throw new GlobalException(ErrorCode.COLLECTION_IS_SOLD_OUT);
        }
        Assert.isTrue(ObjectUtil.isNotNull(productStock) && productStock.getUsableCount() >= count, () -> new GlobalException("库存不足"));

        //优先购次数
        DateTime now = DateTime.now();
        //商品是暂未开始
        if (now.isBefore(digitalCollectionProductInfo.getBeginTime())) {
            Boolean isPriorityPurchase = digitalCollectionProductInfo.getIsPriorityPurchase();
            Boolean isRushBuy = digitalCollectionProductInfo.getIsRushBuy();
            //时间在优先购的时间段内
            if (isPriorityPurchase && now.isBefore(digitalCollectionProductInfo.getPriorityPurchaseEndTime()) && now.isAfter(digitalCollectionProductInfo.getPriorityPurchaseBeginTime())) {
                List<Order> orders = orderDao.getListByProductIdAndStaus(digitalCollectionProductInfo.getId(), OrderStatusEnum.PAYMENT, userInfo.getId(), Boolean.TRUE);
                Integer sumCount = orders.stream().mapToInt(Order::getCount).sum();
                Integer priorityPurchaseLimit = digitalCollectionProductInfo.getPriorityPurchaseLimit();
                if (sumCount + count > priorityPurchaseLimit) {
                    throw new GlobalException(ErrorCode.PREEMPTIVE_PURCHASES_ARE_ONLINE);
                }
                type = 1;
                //时间在优先抢的时间段内
            } else if (isRushBuy && now.isBefore(digitalCollectionProductInfo.getRushBuyEndTime()) && now.isAfter(digitalCollectionProductInfo.getRushBuyBeginTime())) {
                Integer sumCount = orderDao.getRushBuySumByProductIdAndStausAndUserId(digitalCollectionProductInfo.getId(), userInfo.getId());
                Integer priorityPurchaseLimit = digitalCollectionProductInfo.getRushBuyLimit();
                Integer all = sumCount + count;
                if (all > digitalCollectionProductInfo.getUpperLimit() || all > priorityPurchaseLimit) {
                    throw new GlobalException(ErrorCode.PREEMPTIVE_RUSHBUY_ARE_ONLINE);
                }
                type = 2;
            } else {//不在优先购 不在优先抢
                String key = RedisKeyEnum.ILLEGAL_RUSH_BUYING_COUNTER.getKey() + userInfo.getId();
                String v = (String) redisTemplate.opsForValue().get(key);
                if (v == null) {
                    redisTemplate.opsForValue().increment(key);
                    redisTemplate.expire(key, 5, TimeUnit.SECONDS);
                    throw new GlobalException(ErrorCode.NOT_BEGIN);
                } else {
                    redisTemplate.opsForValue().increment(key);
                    int vCount = Integer.parseInt(v);
                    if (vCount > 5) {
                        if (vCount > 10) {
                            redisTemplate.opsForValue().set(RedisKeyEnum.DEROGATION_OF_POWER.getKey() + userInfo.getId(), "true", 10, TimeUnit.MINUTES);
                        }
                        throw new GlobalException("警告：非法抢购，已被记录，请停止操作！");
                    }
                    throw new GlobalException(ErrorCode.NOT_BEGIN);
                }
            }
        }

        //  购买次数校验
        if (type == 1) { //优先购
            Assert.notEmpty(firstPayDTOs, () -> new GlobalException(ErrorCode.FIRST_PAY_DTO_NULL));
            List<Privilege> privilegeList = privilegeDao.list();
            int sumFirstCount = 0;
            for (OrderFirstPayDTO firstPayDTO : firstPayDTOs) {
                if (firstPayDTO.getCount() == 0) {
                    continue;
                }

                sumFirstCount += firstPayDTO.getCount();
                if (firstPayDTO.getType().equals(0)) {
                    UserCollection userCollection = userCollectionDao.findByUuidOnHold(firstPayDTO.getCollectionUuid(), userInfo.getId());
                    if (userCollection.getUserId().longValue() != userInfo.getId().longValue()) {
                        throw new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND);
                    }
                    Privilege privilege = privilegeList.stream().filter(x -> x.getCollectionId().intValue() == userCollection.getCollectionId().intValue()).findFirst().get();
                    if (ObjectUtil.isNotNull(userCollection) && ObjectUtil.isNotNull(privilege)) {
                        String yearMonth = DateTime.now().toString("yyyyMM");
                        int payTime = privilegeUseLogDao.getFirstCountByRecordMonth(yearMonth, userCollection.getCollectionUuid());
                        //特权卡总数 小于 已使用次数
                        if (privilege.getFirstPayTime() < payTime) {
                            throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                        }
                    }
                    BuyFirstCollection buyFirstCollection = buyFirstCollectionDao.selectByProductIdAndCollectionId(digitalCollectionProductInfo.getId(), userCollection.getCollectionId());
                    if (ObjectUtil.isNull(buyFirstCollection) || buyFirstCollection.getBuyFirstNum() < 1) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                    }
                    List<FirstBuyRecord> firstBuyRecordList = firstBuyRecordDao.getByProductIdAndCollectionUuid(digitalCollectionProductInfo.getId(), userCollection.getCollectionUuid());
                    int sumFirstBuyCount = firstBuyRecordList.stream().mapToInt(FirstBuyRecord::getBuyCount).sum();
                    if (sumFirstBuyCount + firstPayDTO.getCount() > buyFirstCollection.getBuyFirstNum()) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                    }

                } else if (firstPayDTO.getType().equals(1)) {
                    UserCollection userCollection = userCollectionDao.findByUuidOnHold(firstPayDTO.getCollectionUuid(), userInfo.getId());
                    BuyFirstCollection buyFirstCollection = buyFirstCollectionDao.selectByProductIdAndCollectionId(digitalCollectionProductInfo.getId(), userCollection.getCollectionId());
                    if (ObjectUtil.isNull(buyFirstCollection) || buyFirstCollection.getBuyFirstNum() < 1) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                    }
                    List<FirstBuyRecord> firstBuyRecordList = firstBuyRecordDao.getByProductIdAndCollectionUuid(digitalCollectionProductInfo.getId(), userCollection.getCollectionUuid());
                    int sumFirstBuyCount = firstBuyRecordList.stream().mapToInt(FirstBuyRecord::getBuyCount).sum();
                    if (sumFirstBuyCount + firstPayDTO.getCount() > buyFirstCollection.getBuyFirstNum()) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                    }
                } else {
                    BuyFirstUser buyFirstUser = buyFirstUserDao.selectByProductIdAndUserId(digitalCollectionProductInfo.getId(), userInfo.getId());
                    if (ObjectUtil.isNull(buyFirstUser) || buyFirstUser.getBuyFirstNum() < 1) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                    }
                    List<FirstBuyRecord> firstBuyRecordList = firstBuyRecordDao.getByProductIdAndUserId(digitalCollectionProductInfo.getId(), userInfo.getId());
                    int sumFirstBuyCount = firstBuyRecordList.stream().mapToInt(FirstBuyRecord::getBuyCount).sum();
                    if (sumFirstBuyCount + firstPayDTO.getCount() > buyFirstUser.getBuyFirstNum()) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_PAY_NOT_ENOUGH);
                    }
                }
            }
            if (sumFirstCount != count) {
                throw new GlobalRunTimeException(ErrorCode.FIRST_BUY_COUNT_ERROR);
            }

            int sum = orderDao.getFirstPaysumListByProductIdAndStaus(digitalCollectionProductInfo.getId());
            if (digitalCollectionProductInfo.getPriorityPurchaseAllLimit() < sum + count) {
                throw new GlobalRunTimeException(ErrorCode.PREEMPTIVE_FIRSTBUY_ARE_ONLINE);
            }

        } else if (type == 2) { //优先抢

            Assert.notEmpty(orderRushPayDTOS, () -> new GlobalException(ErrorCode.FIRST_RUSH_BUY_DTO_NULL));
            int sumFirstCount = 0;
            for (OrderRushPayDTO orderRushPayDTO : orderRushPayDTOS) {
                if (orderRushPayDTO.getCount() == 0) {
                    continue;
                }
                sumFirstCount += orderRushPayDTO.getCount();
                if (orderRushPayDTO.getType().equals(1)) { //藏品
                    UserCollection userCollection = userCollectionDao.findByUuidOnHold(orderRushPayDTO.getCollectionUuid(), userInfo.getId());
                    RushBuyCollection rushBuyCollection = rushBuyCollectionDao.selectByProductIdAndCollectionId(digitalCollectionProductInfo.getId(), userCollection.getCollectionId());
                    if (ObjectUtil.isNull(rushBuyCollection) || rushBuyCollection.getBuyFirstNum() < 1) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_RUSH_BUY_NOT_ENOUGH);
                    }

                    List<RushBuyRecord> rushBuyRecordList = rushBuyRecordDao.getByProductIdAndCollectionUuid(digitalCollectionProductInfo.getId(), userCollection.getCollectionUuid());
                    int sumFirstBuyCount = rushBuyRecordList.stream().mapToInt(RushBuyRecord::getBuyCount).sum();
                    if (sumFirstBuyCount + orderRushPayDTO.getCount() > rushBuyCollection.getBuyFirstNum()) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_RUSH_BUY_NOT_ENOUGH);
                    }
                } else { //用户
                    RushBuyUser rushBuyUser = rushBuyUserDao.selectByProductIdAndUserId(digitalCollectionProductInfo.getId(), userInfo.getId());
                    if (ObjectUtil.isNull(rushBuyUser) || rushBuyUser.getBuyFirstNum() < 1) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_RUSH_BUY_NOT_ENOUGH);
                    }
                    List<RushBuyRecord> rushBuyRecordList = rushBuyRecordDao.getByProductIdAndUserId(digitalCollectionProductInfo.getId(), userInfo.getId());
                    int sumFirstBuyCount = rushBuyRecordList.stream().mapToInt(RushBuyRecord::getBuyCount).sum();
                    if (sumFirstBuyCount + orderRushPayDTO.getCount() > rushBuyUser.getBuyFirstNum()) {
                        throw new GlobalRunTimeException(ErrorCode.FIRST_RUSH_BUY_NOT_ENOUGH);
                    }
                }
            }
            if (sumFirstCount != count) {
                throw new GlobalRunTimeException(ErrorCode.FIRST_BUY_COUNT_ERROR);
            }

            int sum = orderDao.getRushBuySumListByProductIdAndStaus(digitalCollectionProductInfo.getId());
            if (digitalCollectionProductInfo.getRushBuyLimit() < sum + count) {
                throw new GlobalRunTimeException(ErrorCode.PREEMPTIVE_RUSHBUY_ARE_ONLINE);
            }
        } else {
            List<Order> orders = orderDao.getListByProductIdAndStaus(digitalCollectionProductInfo.getId(), OrderStatusEnum.PAYMENT, userInfo.getId(), Boolean.FALSE);
            Integer sumCount = orders.stream().mapToInt(Order::getCount).sum();

            if (digitalCollectionProductInfo.getCommodityType() == CommodityType.SUBSCRIBE_COMMODITY) {
                // 获取用户中签并且有效的数量.这里获取的中签数量包含着他被锁定的签,因为没付款.付款在上面就会有要求他去付款的了.
                Integer productIdAndUserIdByCount = digitalCollectionProductInfoSubscribeWinBallotDao.getProductIdAndUserIdByCount(digitalCollectionProductInfo.getId(), userInfo.getId());
                // count>中签的所有数量抛出异常
                if (count > productIdAndUserIdByCount) {
                    throw new GlobalRunTimeException(ErrorCode.THE_ORDER_FOR_CHANGING_THE_COLLECTION_HAS_REACHED_THE_UPPER_LIMIT);
                }
            } else {
                Integer upperLimit = digitalCollectionProductInfo.getUpperLimit();
                if (upperLimit == 0) {
                    upperLimit = 20;
                }
                if (sumCount + count > upperLimit) {
                    throw new GlobalRunTimeException(ErrorCode.THE_ORDER_FOR_CHANGING_THE_COLLECTION_HAS_REACHED_THE_UPPER_LIMIT);
                }
            }
        }

        return type;
    }

    private void verificationOrder(Order order) {

        if (ObjectUtil.isEmpty(order)) {
            throw new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND);
        }

        OrderStatusEnum status = order.getStatus();
        if (status.getCode() != OrderStatusEnum.WAIT_PAY.getCode()) {
            throw new GlobalRunTimeException(ErrorCode.THE_ORDER_IS_NOT_PAID);
        }
        if (UserPool.getUser().getId().intValue() != order.getUserId().intValue()) {
            throw new GlobalRunTimeException(ErrorCode.PARAM_ERROR);
        }

    }

    private CreateOrderVO getCreateOrderVO(Order order, Boolean flag) {
        CreateOrderVO createOrderVO = new CreateOrderVO();

        long time = order.getCloseTime().getTime();
        long nowTime = order.getCreateTime().getTime();
        if (flag) {
            nowTime = DateTime.now().getTime();
        }

        time = time - nowTime;
        String purchaseNotes = staticDataDao.getByType("purchase_notes").getValue();
        createOrderVO.setOrderId(order.getId());
        createOrderVO.setPurchaseNotes(purchaseNotes);
        createOrderVO.setOffsetTime(time);
        createOrderVO.setProductNum(order.getProductPrice().stripTrailingZeros().toPlainString());
        createOrderVO.setOrderNo(order.getOrderNo());
        createOrderVO.setNowDate(DateUtil.now());
        createOrderVO.setExpirationTime(DateUtil.offsetMinute(new Date(), 3));
        return createOrderVO;
    }

    /**
     * 获取最高折扣
     *
     * @param userId
     * @param productId
     * @return
     */
    private BigDecimal getMinDiscount(Long userId, Long productId) {
        //折扣集合
        ArrayList<BigDecimal> collectionDiscount = Lists.newArrayList();
        //最大的折扣
        BigDecimal minDiscount = new BigDecimal("1");

        //设置的藏品关联
        List<BuyCollectionDiscount> collectionList = buyCollectionDiscountDao.getMinDiscountByProductId(productId);
        if (collectionList.size() > 0) {
            for (BuyCollectionDiscount buyCollectionDiscount : collectionList) {
                Long collectionBuyFirstId = buyCollectionDiscount.getCollectionBuyFirstId();
                List<UserCollection> collercitonList = userCollectionDao.getListByCollercitonId(userId, collectionBuyFirstId);
                if (collercitonList.size() > 0) {
                    collectionDiscount.add(buyCollectionDiscount.getBuyFirstNum());
                }
            }
        }
        //设置的用户关联
        List<BuyUserDiscount> minDiscountByUserId = buyUserDiscountDao.getMinDiscountByUserId(userId, productId);
        if (minDiscountByUserId.size() > 0) {
            for (BuyUserDiscount buyUserDiscount : minDiscountByUserId) {
                BigDecimal buyFirstNum = buyUserDiscount.getBuyFirstNum();
                collectionDiscount.add(buyFirstNum);
            }
        }

        if (collectionDiscount.size() > 0) {
            minDiscount = Collections.min(collectionDiscount);
        }

        return minDiscount;
    }


}